from . import passport_blue

from flask import request,jsonify,current_app,session,make_response

from info.utils.response_code import RET
from info.utils.captcha.captcha import captcha
from info import redis_store,constants,db
import re,random

from info.models import User

#导入运通讯
from info.libs.yuntongxun import sms

from datetime import datetime


"""
前端页生成验证码编号，并将编号并提交到后台去请求验证码图片
后台生成图片验证码，并把验证码文字内容当作值，验证码编号当作key存储在 redis 中
后台把验证码图片当作响应返回给前端
前端申请发送短信验证码的时候带上第1步验证码编号和用户输入的验证码内容
后台取出验证码编号对应的验证码内容与前端传过来的验证码内容进行对比
如果一样，则向指定手机发送验证码，如果不一样，则返回验证码错误
"""
@passport_blue.route('/image_code')
def generate_image_code():
    """
     生成图片验证码
    1、获取参数，uuid，图片验证码的后缀名，实现多用户同时请求，在数据库中存储的唯一
    2、判断参数是否存在，如果不存在，直接终止视图函数的执行；
    3、调用captcha扩展生成图片验证码；name/text/image
    4、在服务器的redis数据库中存储图片验证码的text；
    5、返回图片本身；使用resp = make_response(image)返回；
    6、修改响应的数据类型
    :return:
    """
    #获取参数，获取uuid
    image_code_id = request.args.get('image_code_id')

    #判断参数是否存在
    if not image_code_id:
        return jsonify(errno=RET.PARAMERR,errmsg='参数缺失')

    #调用函数生成验证码图片
    name,text,image = captcha.generate_captcha()

    try:
        redis_store.setex('ImageCode_'+image_code_id,constants.IMAGE_CODE_REDIS_EXPIRES,text)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR,errmsg='保存图片验证码失败')

    #使用响应对象返回图片验证码本身 ,这个时候redis数据库中应该有相应的image验证吗信息
    else:
        response = make_response(image)

        #设置响应类型
        response.headers['Content-type']='image/jpg'
        return response


"""
发送短信
    1、获取参数，mobile、image_code,image_code_id,
    request.json.get()
    2、判断参数的完整性，三个参数必须全部存在
    3、校验参数是否正确，手机号的格式，使用正则
    4、获取本地存储的真实图片验证码
    5、判断图片验证码是否过期，如果已经过期直接return
    6、删除图片验证码
    7、判断图片验证码是否正确
    8、判断手机号是否已注册
    9、生成六位数的短信验证码随机数
    10、在redis中存储短信随机数；
    11、调用云通讯发送短信，需要保持发送结果
    12、判断发送是否成功
    :return:

"""
#发送短信验证码的视图函数

@passport_blue.route('/sms_code',methods=['POST'])
def send_sms_code():
    # 获取参数，手机号，图片验证码的内容，uuid
    mobile=request.json.get('mobile')
    image_code=request.json.get('image_code')
    image_code_id=request.json.get('image_code_id')

    if not all([mobile,image_code,image_code_id]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数缺失')

    #检查手机号的格式
    if not re.match(r'^1[3456789]\d{9}$',mobile):
        return jsonify(errno=RET.PARAMERR,errmsg='手机号格式错误')

    try:
        real_image_code=redis_store.get('ImageCode_'+image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='获取短信验证码异常')

    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg='图片验证码已经过期')

    #只能让用户比较一次，redis只能get一次，只能立即删除
    try:
        redis_store.delete('ImageCode_'+image_code_id)
    except Exception as e:
        current_app.logger.error(e)

    #比较图片验证码是否正确,忽略大小写
    if image_code.lower() != real_image_code.lower():
        return jsonify(errno=RET.DATAERR, errmsg='图片验证码错误，请重新输入')

    #判断手机号是否已经注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='查询数据库异常')
    if user is not None:
        return jsonify(errno=RET.DATAEXIST,errmsg='手机号已注册')


    #构造短信随机吗
    sms_code = '%06d'%random.randint(0,999999)

    #打印随机数，实现不发送短信也能注册
    print(sms_code)

    #把短信随机数存储到redis数据库中
    try:
        redis_store.setex('SMSCode_'+mobile,constants.SMS_CODE_REDIS_EXPIRES,sms_code)

    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='保存短信验证码异常')

    #调用云通讯发送短信随机数
    try:
        ccp=sms.CCP()

        #调用云通讯发送短信，需要保存发送结果
        result=ccp.send_template_sms(mobile,[sms_code,constants.SMS_CODE_REDIS_EXPIRES/60],1)

    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='发送短信异常')

    #判断发送结果
    if result==0:
        return jsonify(errno=RET.OK, errmsg='发送成功')
    else:
        return jsonify(errno=RET.THIRDERR, errmsg='发送失败')

@passport_blue.route('/register',methods=['POST'])
def register():
    """
    用户注册
    1、获取参数：mobile,sms_code,password
    2、检查参数的完整性
    3、检查手机号的格式
    4、获取本地存储的真实的短信验证码
    5、判断短信验证码是否存在
    6、先比较短信验证码是否正确
    7、删除redis数据库中的短信验证码
    8、判断手机号是否已注册
    9、实例化模型类对象，保存用户的注册信息
    10、提交数据到数据库中，如果发生异常需要进行回滚
    11、把用户的基本信息存入redis缓存中
    12、返回结果

    :return:
    """
    mobile=request.json.get('mobile')
    sms_code=request.json.get('sms_code')
    password=request.json.get('password')

    #检查参数的完整性
    if not all([mobile,sms_code,password]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数不完整')

    # 检查手机号的格式
    if not re.match(r'^1[3456789]\d{9}$',mobile):
        return jsonify(errno=RET.PARAMERR,errmsg='手机号的格式错误')

    #获取本地存储的真实短信验证码
    try:
        real_sms_code=redis_store.get('SMSCode_'+mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='获取真实短信验证码异常')

    if not real_sms_code:
        return jsonify(errno=RET.NODATA,errmsg='短信验证码已过期')

    if real_sms_code != sms_code:
         return jsonify(errno=RET.DATAERR,errmsg='短信验证码错误')

    #删除redis数据库中存储的短信验证码
    try:
        redis_store.delete('SMSCode_'+mobile)
    except Exception as e:
        current_app.logger.error(e)

    #判断手机号是否注册
    try:
        user=User.query.filter(User.mobile==mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据失败')

    if user is not None:
        return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册')

    #构造模型类对象，保存用户信息
    user=User()
    user.mobile=mobile
    user.password=password
    user.nick_name=mobile

    #提交数据到mysql数据库中
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        #如果提交数据异常，则需要进行回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg='保存数据失败')

    #缓存用户信息到redis数据库中，后面直接读取redis，不需要查询mysql数据库
    session['mobile']=mobile
    session['user_id']=user.id
    session['nick_name']=mobile

    #返回结果
    return jsonify(errno=RET.OK,errmsg='注册成功')



#实现用户登录
@passport_blue.route('/login',methods=['POST'])
def login():
    """
       用户登录
       1、获取参数，mobile/password
       2、检查参数的完整性
       3、检查手机号格式
       4、使用mobile查询数据库，确认用户已经注册
       user = User.query.filter_by(mobile=mobile).first()
       5、判断用户是否已注册
       6、调用模型类中的密码校验方法，检查密码是否正确
       7、保存用户的登录时间
       8、缓存用户信息
       session['nick_name'] = user.nick_name
       9、返回结果

       :return:
       """
    mobile=request.json.get('mobile')
    password=request.json.get('password')

    if not all([mobile,password]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数缺失')

    if not re.match(r'^1[3456789]\d{9}$',mobile):
        return jsonify(errno=RET.PARAMERR,errmsg='手机号格式错误')

    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询用户数据异常')

    #用户名和密码一起判断
    if user is None or not user.check_password(password):
        return jsonify(errno=RET.PWDERR,errmsg='用户名或密码错误')

    #记录登录时间
    user.last_login = datetime.now()

    #提交数据到数据库中
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='保存数据失败')

    # 缓存用户信息到redis数据库中
    session['user_id'] = user.id
    session['mobile'] = mobile
    session['nick_name'] = user.nick_name

    #返回结果

    return jsonify(errno=RET.OK, errmsg='登录成功')


#实现用户退出
@passport_blue.route('/logout')
def logout():
    """
      用户退出：如果是前后端分离、并且RESTful(表现层状态转换)风格特点的项目，退出登录的请求方法应该是delete；
      1、清除用户的缓存信息
      :return:
      """
    # 清空redis中用户的缓存信息，session.clear()
    session.pop('user_id',None)
    session.pop('mobile', None)
    session.pop('nick_name', None)
    session.pop('is_admin',None)
    

    return jsonify(errno=RET.OK,errmsg='OK')


